#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ghttp.h>
#include <ghttp_constants.h>

#include "imc_http.h"
#include "imc.h"
#include "imc_mng.h"
#include "../../dprint.h"
#include "cJSON.h"

#define BODY_SIZE   256
#define MEM_LEN     32
#define CODE_LEN    7

#define HTTP_200    200
#define JSON_CODE   "000000"

char sbody[BODY_SIZE] = {0};

/* member list */
typedef struct mem{
    char    name[MEM_LEN];
    struct mem* next;
} mem;

static void add_mem(mem** head, double val)
{
    mem* sub = (mem*)shm_malloc(sizeof(mem));
    if(sub == NULL){
        *head = NULL;
        return;
    }
    memset(sub, 0, sizeof(mem));
    sub->next = NULL;
    sprintf(sub->name, "%.lf", val);
    if(*head == NULL)
        *head = sub;
    else{
        sub->next = *head;
        *head = sub;
    }
}

static void desc_mem(mem** head)
{
    if(*head == NULL)
        return;
    mem* sub = NULL;
    for(sub=*head; sub ; sub = *head)
    {
        *head = sub->next;
        shm_free(sub);
    }
    *head = NULL;
}

static int http_parse(char* buf,char* param ,mem** head)
{
    int i = 0;
    *head = NULL;
    if(buf == NULL)
        return -1;
    cJSON *root = cJSON_Parse(buf);
    if(root == NULL)
        return -1;
    cJSON *code = cJSON_GetObjectItem(root, "code");
    if(code == NULL)
        return -1;
    strcpy(param, code->valuestring);
    cJSON *data = cJSON_GetObjectItem(root, "data");
    if(data == NULL)
        return -1;
    int num = cJSON_GetArraySize(data);
    for(i=0; i<num; ++i)
    {
        cJSON *psub = cJSON_GetArrayItem(data, i);
        cJSON *puid = cJSON_GetObjectItem(psub, "uid");
        if(puid->type == cJSON_Number)
            add_mem(head, puid->valuedouble);
    }
    cJSON_Delete(root);
    return 0;
}


/*  URL codec 
 *  src : source string
 *  src_len: source string length
 *  dst : destination string 
 *  dst_len : destination string length
 * */
static int urlencode(char* src, int src_len, char* dst, int dst_len)
{
    int i = 0, j = 0;
    char urls[] = "0123456789ABCDEF";

    for(i=0; i<src_len && j< dst_len ; ++i, ++j)
    {
        char c = src[i];
        if((c < '0' && c != '-' && c != '.') || (c < 'A' && c > '9' && c != '=')||(c > 'Z' && c < 'a' && c != '_')||(c > 'z'))
        {
            dst[j++] = '%';
            dst[j++] = urls[(src[i] >> 4) & 0x0f];
            dst[j] = urls[src[i] & 0x0f];
        }
        else
        {
            dst[j] = src[i];
        }
    }
        
    LM_INFO("i = %d, j = %d, src_len = %d, dst_len = %d\n",i,j,src_len,dst_len);

    if(i < src_len && j == dst_len)
    {
        LM_INFO("dst too short");
        dst[j-1] = '\0';
        return j-1;
    }
    dst[j] = '\0';
    return j;

}


imc_room_p imc_http_inquire_room(str* name, str* domain)
{
    LM_DBG("imc_http_inquire_room: start inquire!\n");
    ghttp_request   *req = NULL;
    ghttp_status    status;


    char code[CODE_LEN] = {0};
    char *buf = NULL;
    int  http_code = 0;
    char *body = (char*)shm_malloc(BODY_SIZE);
    if(body == NULL)
        return NULL;
    memset(body, 0, BODY_SIZE);
    memset(sbody, 0, BODY_SIZE);

    req = ghttp_request_new();
    if(req == NULL)
    {
        shm_free(body);
        return NULL;
    }

    if(ghttp_set_uri(req, remote_http_url.s) == -1)
    {
        goto error;
    }
    if(ghttp_set_type(req, ghttp_type_post) == -1)
        goto error;
    ghttp_set_header(req, http_hdr_Connection, "Keep-Alive");
    ghttp_set_header(req, http_hdr_Content_Type, "application/x-www-form-urlencoded");

    sprintf(sbody, "pa={\"groupId\":\"%.*s\",\"pageSize\":\"30\",\"page\":\"1\"}", name->len, name->s);
    LM_DBG("http body:%s", sbody);
    urlencode(sbody, strlen(sbody), body, BODY_SIZE);
    ghttp_set_body(req, body, strlen(body));
    ghttp_prepare(req);

    status = ghttp_process(req);
    if(status == ghttp_error)
    {
        shm_free(body);
        return 0;
    }
    http_code = ghttp_status_code(req);
    if(http_code != HTTP_200)
        goto error;

    buf = ghttp_get_body(req);
    //buf_len = ghttp_get_body_len(req);

    if(buf == NULL)
        goto error;
    /* 解析buf json */
    mem* head = NULL;
    http_parse(buf, code, &head);
    LM_DBG("code is : %s ", code);
    if(strcmp(code, JSON_CODE) || (head == NULL))
    {
        LM_DBG("not inquer data\n");
        goto error;
    }
    /* 将解析的用户添加到聊天室 */
    mem* sub = NULL;
    imc_room_p imc_room = NULL;
    imc_room = imc_add_room(name, domain);
    if(NULL == imc_room)
    {
        LM_ERR("failed to add room[%.*s]!\n", name->len, name->s);
        goto error;
    }

    str member = {NULL, 0};
    imc_member_p    imc_member = NULL;
    for(sub = head; sub; sub=sub->next)
    {
        LM_DBG("member name: %s \n", sub->name);
        member.s = sub->name;
        member.len = strlen(sub->name);

        imc_member = imc_add_member(imc_room, &member, domain);
        if(imc_member == NULL)
        {
            LM_ERR("failed to add mem[%.*s]", member.len, member.s);
            imc_release_room(imc_room);
            desc_mem(&head);
            imc_del_room(name, domain);
            goto error;
        }
        LM_DBG("add the member [%.*s] success in the room[%.*s]!\n", member.len, member.s, name->len, name->s);
    }
    
    desc_mem(&head);
    ghttp_clean(req);
    shm_free(body);
    return imc_room;
error:
    shm_free(body);
    ghttp_clean(req);
    return NULL;
}
